package edu.bath.sensorframework.client;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.pubsub.Node;
import org.jivesoftware.smackx.pubsub.PubSubManager;

import edu.bath.sensorframework.Config;

public class SensorClient {
	private PubSubManager mgr = null;
	private Map<String,List<String>> rawPendingData;
	private String myJID;
	private ReadingReceiver handler;
	private Connection connection;
	private String username, password;
	private Map<String, List<ReadingHandler>> handlersList;
	
	public SensorClient(String serverAddress, String serverName, String id, String password, String myJID) throws XMPPException {
		Config.configure();
		connection = new XMPPConnection(serverAddress);
		connection.connect();
		connection.login(id, password);
		this.username = id; this.password = password;
		this.mgr = new PubSubManager(connection, "pubsub."+serverName);
		this.myJID = myJID;
		this.rawPendingData = Collections.synchronizedMap(new HashMap<String, List<String>>());
		this.handlersList = Collections.synchronizedMap(new HashMap<String, List<ReadingHandler>>());
		this.handler = new ReadingReceiver(rawPendingData, handlersList);
	}
	
	public void subscribe(String nodeName) throws XMPPException {
		Node node = mgr.getNode(nodeName);
		node.addItemEventListener(handler);
		node.subscribe(myJID);
		this.rawPendingData.put(nodeName, new ArrayList<String>(10));
	}
	
	public void unsubscribe(String nodeName) throws XMPPException {
		Node node = mgr.getNode(nodeName);
		node.removeItemEventListener(handler);
		node.unsubscribe(myJID);
	}
	
	public List<String> getPendingData(String nodeID) {
		if(this.rawPendingData.get(nodeID) == null)
			return new ArrayList<String>(0);
		
		List<String> newList = new ArrayList<String>(this.rawPendingData.get(nodeID).size());
		newList.addAll(this.rawPendingData.get(nodeID));
		this.rawPendingData.clear();
		return newList;
	}
	
	public boolean isPendingData(String nodeID) {
		if(this.rawPendingData.get(nodeID) == null)
			return false;
		
		return (this.rawPendingData.get(nodeID).size()==0?false:true);
	}
	
	public boolean checkReconnect() throws XMPPException {
		boolean output = false;
		if(!connection.isConnected()) {
			System.out.println("Not connected!");
			connection.connect();
			output = true;
		}
		if(!connection.isAuthenticated()) {
			System.out.println("Not authenticated!");
			connection.login(username, password);
			output = true;
		}
		return output;
	}
	
	public void addHandler(String nodeID, ReadingHandler handler) {
		List<ReadingHandler> handlers = this.handlersList.get(nodeID);
		if(handlers == null) {
			handlers = Collections.synchronizedList(new ArrayList<ReadingHandler>(3));
			this.handlersList.put(nodeID, handlers);
		}
		
		handlers.add(handler);
	}
}

